#set( $symbol_pound = '#' )
#set( $symbol_dollar = '$' )
#set( $symbol_escape = '\' )
package ${package}.basic.security;


import ${package}.basic.security.oauth2.config.YkSecurityProperties;
import ${package}.basic.security.oauth2.handler.AuthenticationFailHandlerImpl;
import ${package}.basic.security.oauth2.handler.AuthenticationSuccessHandlerImpl;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.boot.web.servlet.FilterRegistrationBean;
import org.springframework.context.annotation.Bean;
import org.springframework.context.annotation.Configuration;
import org.springframework.security.authentication.AuthenticationManager;
import org.springframework.security.config.annotation.authentication.builders.AuthenticationManagerBuilder;
import org.springframework.security.config.annotation.method.configuration.EnableGlobalMethodSecurity;
import org.springframework.security.config.annotation.web.builders.HttpSecurity;
import org.springframework.security.config.annotation.web.configuration.EnableWebSecurity;
import org.springframework.security.config.annotation.web.configuration.WebSecurityConfigurerAdapter;
import org.springframework.security.core.userdetails.UserDetailsService;
import org.springframework.security.crypto.password.PasswordEncoder;
import org.springframework.security.web.authentication.UsernamePasswordAuthenticationFilter;
import org.springframework.security.web.authentication.rememberme.JdbcTokenRepositoryImpl;
import org.springframework.security.web.authentication.rememberme.PersistentTokenRepository;

import javax.annotation.Resource;
import javax.sql.DataSource;

/**
 * Description: Spring Security的配置类, 用于资源保护
 *
 * @author wupanhua
 * @date 2019/8/6 15:28
 *
 * <pre>
 *              ${copyright}
 *      Copyright (c) 2019. All Rights Reserved.
 * </pre>
 */
@Configuration
@EnableWebSecurity
@EnableGlobalMethodSecurity(prePostEnabled = true)
public class SecurityConfigurer extends WebSecurityConfigurerAdapter {

    /**
     * 登陆失败处理器
     */
    private AuthenticationFailHandlerImpl authenticationFailHandler;
    /**
     * 登陆成功处理器
     */
    private AuthenticationSuccessHandlerImpl authenticationSuccessHandler;
    /**
     * 登陆逻辑
     */
    private UserDetailsService userDetailsService;
    /**
     * 密码加密解密器
     */
    private PasswordEncoder passwordEncoder;
    /**
     * 数据库数据源
     */
    private DataSource dataSource;
    /**
     * 安全配置
     */
    private YkSecurityProperties ykSecurityProperties;


	@Resource
	private FilterRegistrationBean rsaFilterRegister;

    /**
     * Description:
     * <配置如何通过拦截器保护我们的请求，哪些能通过哪些不能通过,允许对特定的http请求基于安全考虑进行配置>
     * Note: if your Authorization Server is also a Resource Server then
     * there is another security filter chain with lower priority controlling the API resources.
     * For those requests to be protected by access tokens you need their paths
     * *not to be* matched by the ones in the main user-facing filter chain,
     * so be sure to include a request matcher that picks out only non-API resources in the WebSecurityConfigurer above.
     * @author ywh
     * @date 13:35 2019/8/7
     * @param httpSecurity 1
     **/
    @Override
    protected void configure(HttpSecurity httpSecurity) throws Exception {
	    httpSecurity
			    .addFilterBefore(rsaFilterRegister.getFilter(), UsernamePasswordAuthenticationFilter.class)
			    .csrf().disable()
			    .cors().disable()
            .formLogin()
		        .loginPage(ykSecurityProperties.getOssLoginPage())
		        // 当请求为如下链接时，视为请求登陆
		        .loginProcessingUrl(ykSecurityProperties.getLoginProcessUrl())
		        // 登陆成功跳转的方法
		        .successHandler(authenticationSuccessHandler)
		        // 登陆失败跳转的方法
                .failureHandler(authenticationFailHandler)
		        .permitAll()
		        .and()
		        .authorizeRequests()
		        /*
		         Note: if your Authorization Server is also a Resource Server then there is another security filter
		         chain with lower priority controlling the API resources. Fo those requests to be protected by access
		         tokens you need their paths not to be matched by the ones in the main user-facing filter chain, so
		         be sure to include a request matcher that picks out only non-API resources in the WebSecurityConfigurer above.
		        **/
			    .antMatchers("/yk_api/**", "/code/**").permitAll()
			    .antMatchers(ykSecurityProperties.getAllowPath()).permitAll()
		        .anyRequest().authenticated()
        ;
    }

    /**
     * Description:
     * <配置一个AuthenticationManagerBuilder用于构建AuthenticationManager>
     * @author wenxiaopeng
     * @date 19:05 2020/04/12
     * @param auth 1
     * @return void
     **/
    @Override
    protected void configure(AuthenticationManagerBuilder auth) throws Exception {
        auth.userDetailsService(userDetailsService).passwordEncoder(passwordEncoder);
    }

    /**
     * Description:
     * <使用AuthenticationManagerBuilder构建一个AuthenticationManager>
     * @author wenxiaopeng
     * @date 19:06 2020/04/12
     * @return org.springframework.security.authentication.AuthenticationManager
     **/
    @Bean
    @Override
    public AuthenticationManager authenticationManagerBean() throws Exception {
        return super.authenticationManagerBean();
    }

    /**
     * Description:
     * <remember me>
     * @author wenxiaopeng
     * @date 19:07 2020/04/21
     * @return org.springframework.security.web.authentication.rememberme.PersistentTokenRepository
     **/
    @Bean
    public PersistentTokenRepository persistentTokenRepository(){
        JdbcTokenRepositoryImpl repository = new JdbcTokenRepositoryImpl();
        repository.setDataSource(dataSource);
        return repository;
    }

    @Autowired
    public void setAuthenticationFailHandler(AuthenticationFailHandlerImpl authenticationFailHandler) {
        this.authenticationFailHandler = authenticationFailHandler;
    }
    @Autowired
    public void setUserDetailsService(UserDetailsService userDetailsService) {
        this.userDetailsService = userDetailsService;
    }
    @Autowired
    public void setPasswordEncoder(PasswordEncoder passwordEncoder) {
        this.passwordEncoder = passwordEncoder;
    }
    @Autowired
    public void setDataSource(DataSource dataSource) {
        this.dataSource = dataSource;
    }
    @Autowired
    public void setYkSecurityProperties(YkSecurityProperties ykSecurityProperties) {
        this.ykSecurityProperties = ykSecurityProperties;
    }
    @Autowired
    public void setAuthenticationSuccessHandler(AuthenticationSuccessHandlerImpl authenticationSuccessHandler) {
        this.authenticationSuccessHandler = authenticationSuccessHandler;
    }

}
